package website.web;
 
import java.beans.XMLDecoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import javax.swing.JPopupMenu.Separator;

import JarJunit.FailedTestResult;
import JarJunit.JarJunitResult;

import com.amazonaws.services.dynamodb.model.AttributeValue;

import cloudjunit.Config;

import cloudjunit.S3FileManager;
import cloudjunit.WorkflowExecutionStarter;
import dynamojunit.DynamoDbCommon;
import dynamojunit.TestClassTable;
import dynamojunit.UserSessionTable;
import dynamojunit.WorkflowTable;

 
@WebServlet("/home")
@MultipartConfig(fileSizeThreshold=1024*1024, maxFileSize=1024*1024*50, maxRequestSize=1024*1024*5*5)
public class MainServlet extends HttpServlet {
	
	
	public MainServlet()
	{
		super();
		cloudjunit.Config.initConfigWithDefaults(ConfigWeb.DEFAULT_AWS_ACCESS_KEY, ConfigWeb.DEFAULT_AWS_SECRET_KEY, ConfigWeb.DEFAULT_S3_INPUT_BUCKET_NAME, ConfigWeb.DEFAULT_SWF_DOMAIN_NAME);
	}
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		PrintWriter out = response.getWriter();
		HttpSession session = request.getSession();
		if (session == null)
		{
			return;
		}
		
		String sessionId  = session.getId();
		String query_string = request.getQueryString();
		
		if (query_string==null)
		{
			out.flush();
		    out.close();
		    return;
		}
		
		if (query_string.contains("action=status"))
		{
			String status_resp=JarJunitSessionManager.get_session_status(sessionId);
			out.println(status_resp.toString());
		}
		else if (query_string.contains("action=init"))
		{
			JarJunitSessionManager.init_session(sessionId);
		}
		else if (query_string.contains("action=show-results"))
		{
			StringBuffer resp_buff = write_results(sessionId);
			out.println(resp_buff.toString());
		}
		else if (query_string.contains("action=show-test-trace"))
		{
			StringBuffer resp_buff = write_test_trace_result(sessionId, query_string);
			out.println(resp_buff.toString());
		}
		
	    out.flush();
	    out.close();
	}
 
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html");
		PrintWriter out = resp.getWriter();
		
		Collection<Part> parts = request.getParts();
		
		if (parts.size()!=1)
		{
			out.write("<h2>ERROR</h2>");
			return;
		}
		
		for(Part part : parts) {
			//TODO: run in a new thread
			start_workflow_for_session(request.getSession().getId(), part);
		}
		
	}
	
	private void start_workflow_for_session(String sessionId, Part part) throws IOException
	{	
		String remote_s3_file_path = upload_jar_file_to_s3(part);
		
		WorkflowExecutionStarter workflow_starter = new WorkflowExecutionStarter(sessionId,remote_s3_file_path);
    	workflow_starter.go();
	}
	
	
	private String create_temp_file(String prefix, String temp_dir_str) throws IOException
	{
		File temp_dir = new File(temp_dir_str);
		File f = File.createTempFile(prefix,"",temp_dir);
		return temp_dir_str+f.getName();
	}
	
	private String upload_jar_file_to_s3(Part part_file) throws IOException
	{
		//write file to File System
		String original_file_path = get_file_name_from_part(part_file);
		String[] subDirs = original_file_path.split(Pattern.quote(File.separator));
		String jar_file_name = subDirs[subDirs.length-1];
		
		String temp_dir_str = System.getProperty("java.io.tmpdir");
		String jar_local_file_path = create_temp_file("jar_",temp_dir_str);
		part_file.write(jar_local_file_path);
		
		String rand_generated_remote_file_name = UUID.randomUUID().toString();
		String remote_s3_file_path = ConfigWeb.S3_INCOMING_JAR_FOLDER + "/" +rand_generated_remote_file_name;
		S3FileManager.get().uploadFileToS3(Config.data.defaultS3Bucket, jar_local_file_path, remote_s3_file_path);
		
		//delete after upload
		File jar_file = new File(jar_local_file_path);
		jar_file.delete();
		
		return remote_s3_file_path;
	}
	
	private String get_file_name_from_part(Part part) throws IOException
	{
		String bla = "content-disposition";
		for(String header : part.getHeaderNames()) {
			if (header.equals(bla))
			{
				String header_data = part.getHeader(header);
				String file_name_with_quotes = (header_data.split("filename="))[1];
				String file_name = file_name_with_quotes.replace("\"","");
				return file_name;
			}
		}
		throw new IOException("error no file name");
	}
	
	private StringBuffer write_results(String session_id)
	{
		StringBuffer resp_buff = new StringBuffer();
		
		//get wfid
		UserSessionTable session_table = new UserSessionTable(false);
		String wfid = session_table.getSessionCurrentWorkflowId(session_id);
		if (wfid == "")
		{
			return resp_buff;
		}
		WorkflowTable workflow_table = new WorkflowTable(false);
		if (!workflow_table.isWorkFlowIdExist(wfid))
		{
			return resp_buff;
		}
		//get tcid
		Map<String, AttributeValue> values_map = workflow_table.readWorkflowEntry(wfid);
		List<String> test_classes_ids = workflow_table.readTestClassesIdsList(values_map);
		
		if (test_classes_ids.size() != 0)
		{
			//read individual test classes
			TestClassTable test_class_table = new TestClassTable(false);
			for (String tcid: test_classes_ids)
			{
				Map<String, AttributeValue> test_class_values_map = test_class_table.readTestClassEntry(tcid);
				String class_name = test_class_table.readClassName(test_class_values_map);
				String num_ok = test_class_table.readNumberOfPassedTests(test_class_values_map);
				String num_failed = test_class_table.readNumberOfFailedTests(test_class_values_map);
				List<String> list_passed_methods = test_class_table.readPassedTestsList(test_class_values_map);
				List<String> list_failed_methods = test_class_table.readFailedTestsList(test_class_values_map);
				
				if ((class_name!="")&&(num_ok!="")&&(num_failed!=""))
				{
					resp_buff.append(create_test_class_record(class_name, num_ok, num_failed));
					resp_buff.append(create_methods_report(class_name, list_passed_methods, list_failed_methods));
				}
			}
		}
		
		return resp_buff;
	}
	
	private String create_test_class_record(String class_name, String num_ok, String num_failed)
	{
		int total_num_of_tests = Integer.parseInt(num_ok)+Integer.parseInt(num_failed);
		
		String[] splits = class_name.split(Pattern.quote("/"));
		String class_name_with_suffix =  splits[splits.length-1];
		String package_name = "default";
		if (splits.length != 1)
		{
			package_name = class_name.replace('/', '.');
			package_name = package_name.substring(0, package_name.length()-class_name_with_suffix.length()-1);
		}
		
		String class_name_no_suffix = class_name_with_suffix.substring(0, class_name_with_suffix.length()-6);
		
		String record = "<h3><a href='#'>"+class_name_no_suffix+"     [package:"+package_name+"] "+num_ok.toString()+"/"+Integer.toString(total_num_of_tests)+"</a></h3>\n";
		return record;
	}
	
	private String create_methods_report(String class_name, List<String> passed_tests_list, List<String> failed_tests_list)
	{
		String record = "<div>\n";
		record+= "<ul>\n";
		
		for (String passed_method_name: passed_tests_list)
		{
			record+="<li><img src='images/check16.png'/>   "+passed_method_name+"</li>\n";	
		}
		
		for (String failed_method_name: failed_tests_list)
		{
			String embedded_method_id = class_name+"-"+failed_method_name;
			record+="<li><img src='images/error16.png'/>  "+failed_method_name+"   <img src='images/list16.png' class='list-error' onclick='get_trace(\""+embedded_method_id+"\")'/></li>\n";	
		}
		
		record+= "</ul>\n";
		record += "</div>\n";
		
		return record;
	}
	
	private StringBuffer write_test_trace_result( String session_id, String query_str) throws IOException
	{
		StringBuffer resp_buff = new StringBuffer();
		
		//get test id from query string
		String test_id = "";
		String[] splits = query_str.split(Pattern.quote("&"));
		for (String split: splits)
		{
			if (split.contains("test-id="))
			{
				test_id = split.split(Pattern.quote("="))[1];
				break;
			}
		}
		if (test_id == "")
			return resp_buff;
		
		//download xml result file to temp local storage and parse results
		//get wfid
		UserSessionTable session_table = new UserSessionTable(false);
		String wfid = session_table.getSessionCurrentWorkflowId(session_id);
		if (wfid == "")
		{
			return resp_buff;
		}
		WorkflowTable workflow_table = new WorkflowTable(false);
		if (!workflow_table.isWorkFlowIdExist(wfid))
		{
			return resp_buff;
		}
		
		//get tcid
		String test_method_name =  test_id.split(Pattern.quote("-"))[1];
		String test_class_name =  test_id.split(Pattern.quote("-"))[0];
		String tcid = DynamoDbCommon.convertTestClassToTCID(test_class_name, wfid);
		TestClassTable test_class_table = new TestClassTable(false);
		Map<String, AttributeValue> test_class_values_map = test_class_table.readTestClassEntry(tcid);
		String remote_S3_results_path = test_class_table.readRemoteS3TestResultsPath(test_class_values_map);
		
		//download to temp dir
		
		String temp_dir_str = System.getProperty("java.io.tmpdir");
		String results_file_local_path = create_temp_file("xml_", temp_dir_str);
		String results_file_local_name = UUID.randomUUID().toString();
		String results_file_full_path = results_file_local_path+results_file_local_name;
		
		S3FileManager.get().downloadFileFromS3(Config.data.defaultS3Bucket, remote_S3_results_path, results_file_full_path);
		
		FileInputStream os = new FileInputStream(results_file_full_path);
		XMLDecoder decoder = new XMLDecoder(os);
		JarJunitResult test_result = (JarJunitResult)decoder.readObject();
		
		List<FailedTestResult> failed_list = test_result.getFailedTestsList();
		for (FailedTestResult failed_test: failed_list)
		{
			String method_name = failed_test.getTestName();
			method_name = method_name.split(Pattern.quote("("))[0];
			
			if (method_name.equals(test_method_name))
			{
				String trace = failed_test.getTestTrace();
				trace  = trace.replaceAll("(<)", "{");
				trace  = trace.replaceAll("(>)", "}");
				trace  = trace.replaceAll("(\n)", "<br />");
				trace  = trace.replaceAll("(\n)", "<br />");
				trace  = trace.replaceAll("(\r)", "&nbsp&nbsp&nbsp&nbsp");
				resp_buff.append(trace);
			}
		}
		
		decoder.close();
		
		//delete after upload
		File temp = new File(results_file_full_path);
		temp.delete();
		
		return resp_buff;
	}
}